package Core;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class CharacterClassFactoryImpl implements CharacterClassFactory
{
	private static CharacterClassFactory _instance;
	public static CharacterClassFactory getInstance()
	{
		if (_instance == null)
		{
			_instance = new CharacterClassFactoryImpl();
		}
		
		return _instance;
	}
	
	
	private List<CharacterClass> _classes;
	
	private CharacterClassFactoryImpl()
	{
		this.initializeClasses();
	}
	
	@Override
	public CharacterClass getClassByName(String name)
	{
		CharacterClass foundClass = null;

		for (Iterator<CharacterClass> iterator = this._classes.iterator(); iterator.hasNext(); )
		{
			CharacterClass currentClass = iterator.next();
			
			if (currentClass.getName() == name)
			{
				foundClass = currentClass;
				break;
			}
		}
		
		return foundClass;
	}

	@Override
	public CharacterClass[] getAllClasses()
	{
		return this._classes.toArray(new CharacterClass[0]);
	}
	
	private void initializeClasses()
	{
		this._classes = new ArrayList<CharacterClass>();
		
		this.initializeWarriors();
		this.initializeHealers();
		this.initializeCasters();
		this.initializeStrikers();
	}

	private void initializeWarriors()
	{
		this.initializeBarbarian();
		this.initializeKnight();
		this.initializeMonk();
		this.initializeTemplar();
	}
	
	private void initializeHealers()
	{
		initializeCleric();
		initializeCrusader();
		initializeShaman();
		initializeDruid();
	}
	
	private void initializeCasters()
	{
		initializeSorcerer();
		initializeWarlock();
		initializeIncarnate();
		initializeMentalist();
	}
	
	private void initializeStrikers()
	{
		initializeScout();
		initializeSwashbuckler();
		initializeRogue();
		initializeRanger();
	}
	
	private void initializeBarbarian()
	{
		List<LevelSnapshot> levels = new ArrayList<LevelSnapshot>();

		levels.add(this.createLevelSnapshot(1, 3, 12, 1, 0, 0));
		levels.add(this.createLevelSnapshot(1, 3, 12, 1, 1, 0));
		levels.add(this.createLevelSnapshot(1, 3, 12, 1, 0, 1));
		levels.add(this.createLevelSnapshot(1, 3, 12, 1, 1, 0));
		levels.add(this.createLevelSnapshot(1, 3, 12, 1, 0, 0));
		levels.add(this.createLevelSnapshot(1, 3, 12, 1, 1, 1));
		levels.add(this.createLevelSnapshot(1, 3, 12, 1, 0, 0));
		levels.add(this.createLevelSnapshot(1, 3, 12, 1, 1, 0));
		levels.add(this.createLevelSnapshot(1, 3, 12, 1, 0, 1));
		levels.add(this.createLevelSnapshot(1, 3, 12, 1, 1, 0));
		levels.add(this.createLevelSnapshot(1, 3, 12, 1, 0, 0));
		levels.add(this.createLevelSnapshot(1, 3, 12, 1, 1, 0));
		levels.add(this.createLevelSnapshot(1, 3, 12, 1, 0, 1));
		levels.add(this.createLevelSnapshot(1, 3, 12, 1, 1, 0));
		levels.add(this.createLevelSnapshot(1, 3, 12, 1, 0, 0));
		levels.add(this.createLevelSnapshot(1, 3, 12, 1, 1, 0));
		levels.add(this.createLevelSnapshot(1, 3, 12, 1, 0, 1));
		levels.add(this.createLevelSnapshot(1, 3, 12, 1, 1, 0));
		levels.add(this.createLevelSnapshot(1, 3, 12, 1, 0, 0));
		levels.add(this.createLevelSnapshot(1, 3, 12, 1, 1, 0));
		levels.add(this.createLevelSnapshot(1, 3, 12, 1, 0, 1));
		levels.add(this.createLevelSnapshot(1, 3, 12, 1, 1, 0));
		levels.add(this.createLevelSnapshot(1, 3, 12, 1, 0, 0));
		levels.add(this.createLevelSnapshot(1, 3, 12, 1, 1, 0));
		levels.add(this.createLevelSnapshot(1, 3, 12, 1, 0, 1));

		CharacterClass barbarian = this.createClass("Barbarian", levels);
		
		this._classes.add(barbarian);
	}
	
	private void initializeKnight()
	{
		List<LevelSnapshot> levels = new ArrayList<LevelSnapshot>();
		
		CharacterClass knight = this.createClass("Knight", levels);
		
		this._classes.add(knight);
	}
	
	private void initializeMonk()
	{
		List<LevelSnapshot> levels = new ArrayList<LevelSnapshot>();
		
		CharacterClass monk = this.createClass("Monk", levels);
		
		this._classes.add(monk);
	}
	
	private void initializeTemplar()
	{
		List<LevelSnapshot> levels = new ArrayList<LevelSnapshot>();
		
		CharacterClass templar = this.createClass("Templar", levels);
		
		this._classes.add(templar);
	}
	
	private void initializeCleric()
	{
		List<LevelSnapshot> levels = new ArrayList<LevelSnapshot>();
		
		CharacterClass cleric = this.createClass("Cleric", levels);
		
		this._classes.add(cleric);
	}
	
	private void initializeCrusader()
	{
		List<LevelSnapshot> levels = new ArrayList<LevelSnapshot>();
		
		CharacterClass crusader = this.createClass("Crusader", levels);
		
		this._classes.add(crusader);
	}
	
	private void initializeShaman()
	{
		List<LevelSnapshot> levels = new ArrayList<LevelSnapshot>();
		
		CharacterClass shaman = this.createClass("Shaman", levels);
		
		this._classes.add(shaman);
	}
	
	private void initializeDruid()
	{
		List<LevelSnapshot> levels = new ArrayList<LevelSnapshot>();
		
		CharacterClass druid = this.createClass("Druid", levels);
		
		this._classes.add(druid);
	}
	
	private void initializeSorcerer()
	{
		List<LevelSnapshot> levels = new ArrayList<LevelSnapshot>();
		
		CharacterClass sorcerer = this.createClass("Sorcerer", levels);
		
		this._classes.add(sorcerer);
	}
	
	private void initializeWarlock()
	{
		List<LevelSnapshot> levels = new ArrayList<LevelSnapshot>();
		
		CharacterClass warlock = this.createClass("Warlock", levels);
		
		this._classes.add(warlock);
	}
	
	private void initializeIncarnate()
	{
		List<LevelSnapshot> levels = new ArrayList<LevelSnapshot>();
		
		CharacterClass incarnate = this.createClass("Incarnate", levels);
		
		this._classes.add(incarnate);
	}
	
	private void initializeMentalist()
	{
		List<LevelSnapshot> levels = new ArrayList<LevelSnapshot>();
		
		CharacterClass mentalist = this.createClass("Mentalist", levels);
		
		this._classes.add(mentalist);
	}
	
	private void initializeScout()
	{
		List<LevelSnapshot> levels = new ArrayList<LevelSnapshot>();
		
		CharacterClass scout = this.createClass("Scout", levels);
		
		this._classes.add(scout);
	}
	
	private void initializeSwashbuckler()
	{
		List<LevelSnapshot> levels = new ArrayList<LevelSnapshot>();
		
		CharacterClass swashbuckler = this.createClass("Swashbuckler", levels);
		
		this._classes.add(swashbuckler);
	}
	
	private void initializeRogue()
	{
		List<LevelSnapshot> levels = new ArrayList<LevelSnapshot>();
		
		CharacterClass rogue = this.createClass("Rogue", levels);
		
		this._classes.add(rogue);
	}
	
	private void initializeRanger()
	{
		List<LevelSnapshot> levels = new ArrayList<LevelSnapshot>();
		
		CharacterClass ranger = this.createClass("Ranger", levels);
		
		this._classes.add(ranger);
	}
	
	private CharacterClass createClass(String name, List<LevelSnapshot> levels)
	{
		CharacterClass createdClass = new CharacterClassImpl();
		
		createdClass.setName(name);
		this.setupLevelSnapshots(createdClass, levels);
		this.setupBasicRequirements(createdClass, levels.size());

		return createdClass;
	}

	private void setupLevelSnapshots(CharacterClass newClass, List<LevelSnapshot> levels)
	{
		for (int listIndex = 0; listIndex < levels.size(); listIndex++ )
		{
			int level = listIndex + 1;
			
			LevelSnapshot snapshot = levels.get(listIndex);
			
			newClass.addLevelSnapshot(level, snapshot);
		}
	}
	
	private void setupBasicRequirements(CharacterClass newClass, int maxLevel)
	{
		newClass.addEmptyRequirements(1);
		
		for (int currentLevel = 2; currentLevel <= maxLevel; currentLevel++)
		{
			int requiredLevel = currentLevel - 1;
			
			newClass.addRequirement(currentLevel, new ClassLevelRequirementImpl(newClass, requiredLevel));
		}
	}
	
	private LevelSnapshot createLevelSnapshot(int attackBonus, int manaBonus, int hitPointBonus,
			int fortitudeBonus, int reflexBonus, int willBonus, SpecialAbility... abilities)
	{
		LevelSnapshot snapshot = new LevelSnapshot();
		
		snapshot.setAttackBonus(attackBonus);
		snapshot.setManaBonus(manaBonus);
		snapshot.setHitPointBonus(hitPointBonus);
		snapshot.setFortitudeBonus(fortitudeBonus);
		snapshot.setReflexBonus(reflexBonus);
		snapshot.setWillBonus(willBonus);
		
		for (int abilityIndex = 0; abilityIndex < abilities.length; abilityIndex++ )
		{
			SpecialAbility currentAbility = abilities[abilityIndex];
			
			snapshot.addAbility(currentAbility);
		}
		
		return snapshot;
	}
}
